home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Newswatcher 2.0b22 / NW Source / Source / smtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-24  |  7.6 KB  |  285 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     smtp.c
  4.  
  5.     This reusable module implements SMTP mail.
  6.     
  7.     The following functions are exported:
  8.     
  9.         SmtpOpen - Open an SMTP stream.
  10.         SmtpClose - Close an SMTP stream.
  11.         SmtpSendMessage - Send a mail message.
  12.         
  13.     The following functions are used to get error information:
  14.         
  15.         SmtpGetServerErrInfo - Get server error information.
  16.         SmtpGetOSErr - Get OS error number.
  17.         
  18.     The NetInit function in module net.c must be called before calling any of
  19.     the functions in this module. You also must call the NetIdle function in your
  20.     idle loop, and the NetTerm function at program termination.
  21.         
  22.     A "stream" is an abstraction representing a bidirectional network connection
  23.     to an SMTP server. A stream is represented as a handle of type "SmtpStreamHandle". 
  24.     These stream handles are opaque. You may copy them and pass them as parameters 
  25.     to functions in smtp.c, but you are prohibited from accessing the contents of
  26.     the memory blocks pointed to by the stream handles. Only the functions in 
  27.     smtp.c are permitted to manipulate the contents of these blocks.
  28.     
  29.     The functions return a value of type SmtpErr as the function result:
  30.     
  31.         smtpNoErr            no error occurred
  32.         smtpServerErr        server error
  33.         smtpOSErr            OS error
  34.         
  35.     If the function result is smtpServerErr, the SmtpGetServerErrInfo function should
  36.     be called to get information about the server error. On server errors, the 
  37.     stream is still open on return to the caller (except in SmtpOpen, which creates the
  38.     stream only if no errors of any kind occur).
  39.     
  40.     If the function result is smtpOSErr, the SmtpGetOSErr function should be called
  41.     to get the OS error number:
  42.  
  43.         userCanceledErr        if the user canceled the operation
  44.         other                any other OS, Toolbox, or MacTCP error code
  45.         
  46.     If the user cancels an operation or any other OS error occurs, the stream
  47.     is aborted and deallocated before returning to the caller. "Aborted" means that 
  48.     the server connection is closed abruptly, without going through the usual TCP 
  49.     stream teardown process. You must perform careful error checking. The stream is
  50.     deallocated, and must not be reused.
  51.     
  52.     Copyright © 1994, Northwestern University.
  53.  
  54. ----------------------------------------------------------------------------*/
  55.  
  56. #include <stdlib.h>
  57. #include <string.h>
  58. #include <stdio.h>
  59.  
  60. #include "def.h"
  61. #include "smtp.h"
  62. #include "net.h"
  63. #include "memutil.h"
  64.  
  65.  
  66.  
  67. /* Types. */
  68.  
  69. typedef struct TStream {
  70.     NetStreamHandle netStream;            /* net stream handle */
  71.     Boolean needReset;                    /* true if must send RSET command before
  72.                                            next message */
  73. } TStream, *TStreamPtr, **TStreamHandle;
  74.  
  75.  
  76.  
  77. /*    Global variables. */
  78.  
  79. static OSErr gErr = noErr;            /* OS error code */
  80. static CStr255 gCommand = "";        /* server command */
  81. static long gResponseCode = 0;        /* server response code */
  82. static CStr255 gResponse = "";        /* server response message */
  83.  
  84.  
  85.  
  86. /*----------------------------------------------------------------------------
  87.     SmtpOpen 
  88.     
  89.     Open an SMTP stream.
  90.     
  91.     Entry:    host = server host address (domain name or dotted 
  92.                 decimal IP address).
  93.     
  94.     Exit:    function result = result code.
  95.             stream = handle to opened stream, 
  96.                 or nil if function result != smtpNoErr.
  97. ----------------------------------------------------------------------------*/
  98.  
  99. SmtpErr SmtpOpen (char *host, SmtpStreamHandle *stream)
  100. {
  101.     TStreamHandle s;
  102.     unsigned long addr;
  103.     unsigned short port;
  104.     NetStreamHandle netStream;
  105.     CStr255 myName;
  106.     
  107.     *stream = nil;
  108.     *gCommand = 0;
  109.  
  110.     gErr = NetNameToAddr(host, kSMTPPort, &addr, &port);
  111.     if (gErr != noErr) return smtpOSErr;
  112.     
  113.     gErr = NetOpen(addr, port, &netStream, &gResponseCode, gResponse);
  114.     if (gErr != noErr) return smtpOSErr;
  115.     if (gResponseCode != 220) goto exit1;
  116.     
  117.     gErr = NetGetMyName(myName);
  118.     if (gErr != noErr) {
  119.         if (gErr == userCanceledErr) goto exit2;
  120.         gErr = NetGetMyAddrStr(myName);
  121.         if (gErr != noErr) goto exit2;
  122.     }
  123.     sprintf(gCommand, "HELO %.250s", myName);
  124.     gErr = NetCommand(netStream, gCommand, &gResponseCode, gResponse);
  125.     if (gErr != noErr) return smtpOSErr;
  126.     if (gResponseCode != 250) goto exit1;
  127.     
  128.     gErr = MyNewHandle(sizeof(TStream), &s);
  129.     if (gErr != noErr) goto exit2;
  130.     
  131.     (**s).netStream = netStream;
  132.     (**s).needReset = false;
  133.     
  134.     *stream = (SmtpStreamHandle)s;
  135.     return smtpNoErr;
  136.     
  137. exit1:
  138.  
  139.     NetClose(netStream);
  140.     return smtpServerErr;
  141.     
  142. exit2:
  143.  
  144.     NetClose(netStream);
  145.     return smtpOSErr;
  146. }
  147.  
  148.  
  149.  
  150. /*----------------------------------------------------------------------------
  151.     SmtpClose 
  152.     
  153.     Close an SMTP stream.
  154.     
  155.     Entry:    stream = handle to stream.
  156.     
  157.     Exit:    function result = result code (always smtpNoErr).
  158. ----------------------------------------------------------------------------*/
  159.  
  160. SmtpErr SmtpClose (SmtpStreamHandle stream)
  161. {
  162.     TStreamHandle s;
  163.     
  164.     s = (TStreamHandle)stream;
  165.     NetClose((**s).netStream);
  166.     MyDisposeHandle(s);
  167.     return smtpNoErr;
  168. }
  169.  
  170.  
  171.  
  172. /*----------------------------------------------------------------------------
  173.     SmtpSendMessage 
  174.     
  175.     Send a mail message.
  176.     
  177.     Entry:    stream = handle to stream.
  178.             from = C-format email address of sender.
  179.             to = C-format email address of recipient.
  180.             text = handle to message text, including SMTP header, with CR line 
  181.                 terminators. Warning: the memory block is modified by the function.
  182.                 The memory block must be unlocked and nonpurgeable.
  183.     
  184.     Exit:    function result = result code.
  185.     
  186.     Multiple recipients may be listed in the "to" string, separated by commas.
  187. ----------------------------------------------------------------------------*/
  188.  
  189. SmtpErr SmtpSendMessage (SmtpStreamHandle stream, char *from, char *to, Handle text)
  190. {
  191.     TStreamHandle s;
  192.     NetStreamHandle netStream;
  193.     char *p, *q;
  194.     short len;
  195.     
  196.     s = (TStreamHandle)stream;
  197.     netStream = (**s).netStream;
  198.     
  199.     if ((**s).needReset) {
  200.         strcpy(gCommand, "RSET");
  201.         gErr = NetCommand(netStream, gCommand, &gResponseCode, gResponse);
  202.         if (gErr != noErr) goto exit1;
  203.         if (gResponseCode != 250) goto exit2;
  204.         (**s).needReset = false;
  205.     }
  206.     
  207.     sprintf(gCommand, "MAIL FROM:<%.243s>", from);
  208.     gErr = NetCommand(netStream, gCommand, &gResponseCode, gResponse);
  209.     if (gErr != noErr) goto exit1;
  210.     if (gResponseCode != 250) goto exit2;
  211.     
  212.     p = to;
  213.     while (*p != 0) {
  214.         q = p;
  215.         while (*q != 0 && *q != ',') q++;
  216.         len = q-p;
  217.         if (len > 0 && len <= 245) {
  218.             sprintf(gCommand, "RCPT TO:<%.*s>", len, p);
  219.             gErr = NetCommand(netStream, gCommand, &gResponseCode, gResponse);
  220.             if (gErr != noErr) goto exit1;
  221.             if (gResponseCode != 250 && gResponseCode != 251) goto exit2;
  222.         }
  223.         p = q;
  224.         if (*p == ',') p++;
  225.     }
  226.     
  227.     strcpy(gCommand, "DATA");
  228.     gErr = NetCommand(netStream, gCommand, &gResponseCode, gResponse);
  229.     if (gErr != noErr) goto exit1;
  230.     if (gResponseCode != 354) goto exit2;
  231.     
  232.     gErr = NetSendText(netStream, text);
  233.     if (gErr != noErr) goto exit1;
  234.     
  235.     gErr = NetGetExtraResponse(netStream, &gResponseCode, gResponse);
  236.     if (gErr != noErr) goto exit1;
  237.     if (gResponseCode != 250 && gResponseCode != 251) goto exit2;
  238.     
  239.     return smtpNoErr;
  240.     
  241. exit1:
  242.  
  243.     MyDisposeHandle(s);
  244.     return smtpOSErr;
  245.     
  246. exit2:
  247.  
  248.     (**s).needReset = true;
  249.     return smtpServerErr;
  250. }
  251.  
  252.  
  253.  
  254. /*----------------------------------------------------------------------------
  255.     SmtpGetServerErrInfo 
  256.     
  257.     Get server error information.
  258.     
  259.     Exit:    cmd = C-format server command.
  260.             num = server error number.
  261.             msg = C-format server error message.
  262. ----------------------------------------------------------------------------*/
  263.  
  264. void SmtpGetServerErrInfo (CStr255 cmd, long *num, CStr255 msg)
  265. {
  266.     strcpy(cmd, gCommand);
  267.     *num = gResponseCode;
  268.     strcpy(msg, gResponse);
  269. }
  270.  
  271.  
  272.  
  273. /*----------------------------------------------------------------------------
  274.     SmtpGetOSErr 
  275.     
  276.     Get the OS error code.
  277.     
  278.     Exit:    function result = OS error code.
  279. ----------------------------------------------------------------------------*/
  280.  
  281. OSErr SmtpGetOSErr (void)
  282. {
  283.     return gErr;
  284. }
  285.